Skip to content

Conversation

@Erics1337
Copy link
Contributor

@Erics1337 Erics1337 commented Nov 10, 2025

Replace jQuery tab toggles with Vue reactivity (Fixes #4700)

Overview

Moves tab visibility logic from jQuery to Vue so Expert Mode and feature-based tabs update instantly and stay in sync without DOM flicker.

What changed

  • Added expertMode to the Vue model and bound the checkbox with v-model.
  • Used v-show for visibility:
    • Expert-only: failsafe, adjustments, sensors, logging
    • Build options: servos (USE_SERVOS/USE_WING), gps (USE_GPS)
    • Features: osd, led_strip, transponder via features.isEnabled(...)
  • Removed jQuery .toggle() calls in updateTabList.js; it now just syncs the checkbox to Vue state.

Why

  • One source of truth (Vue) instead of mixing jQuery and Vue.
  • Fewer edge cases during connect/disconnect and tab switching.
  • Simpler and more maintainable—the rules live next to the markup.

Test

  • Toggle Expert Mode: tabs appear/disappear immediately.
  • Connect different FCs: gps/servos/osd/led_strip/transponder tabs reflect build options and features.

Fixes #4700

Summary by CodeRabbit

  • New Features

    • Introduced expert mode toggle to reveal advanced configuration options
  • Changes

    • Tab visibility reorganized: failsafe, sensors, and logging tabs now visible only in expert mode
    • Availability of adjustments, servos, GPS, OSD, transponder, and LED strip tabs depends on firmware build configuration and enabled features

- Moved expert mode state to reactive Vue model for declarative UI updates
- Replaced imperative jQuery .toggle() calls with Vue v-show directives in template
- Simplified updateTabList to only sync checkbox state with Vue model
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 10, 2025

Walkthrough

The changes replace jQuery-based tab visibility logic with Vue reactive state management. An expertMode flag is added to the reactive model, bound to a checkbox in HTML, and tabs are conditionally rendered using Vue's v-show directive based on expertMode or feature flags instead of jQuery DOM manipulation.

Changes

Cohort / File(s) Summary
Vue Reactive State Setup
src/components/init.js
Added expertMode property (initialized to false) to the reactive betaflightModel object to serve as the single source of truth for expert mode visibility state.
HTML Template Updates
src/index.html
Added v-model binding for expertMode on the expert mode checkbox and applied v-show conditional rendering to tabs based on expertMode flag or feature flags (OSDS, TRANSPONDER, LED_STRIP) and build options. Affected tabs: tab_failsafe, tab_adjustments, tab_servos, tab_gps, tab_osd, tab_transponder, tab_led_strip, tab_sensors, tab_logging.
Utility Function Refactor
src/js/utils/updateTabList.js
Removed DOM-based tab visibility logic and replaced with minimal integration that syncs the expert mode checkbox state to the Vue model's expertMode property. Added try/catch wrapper to gracefully handle cases where Vue instance unavailable.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Checkbox as Expert Mode Checkbox
    participant Vue as Vue Reactivity
    participant DOM as Template (v-show)
    
    rect rgb(200, 220, 240)
    Note over User,DOM: Old Approach (jQuery-based)
    User->>Checkbox: Click to toggle
    Checkbox->>updateTabList: jQuery event handler
    updateTabList->>DOM: Directly toggle visibility
    end
    
    rect rgb(240, 200, 220)
    Note over User,DOM: New Approach (Vue-based)
    User->>Checkbox: Click to toggle
    Checkbox->>Vue: v-model updates expertMode
    Vue->>DOM: v-show re-evaluates based on expertMode
    DOM-->>User: Tabs show/hide reactively
    end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

  • Homogeneous pattern changes (same v-show conditional applied across multiple tabs)
  • No complex new logic; primarily template and state management refactoring
  • Straightforward migration from imperative jQuery to declarative Vue reactivity
  • Minor areas for attention:
    • Verify all tab visibility conditions in index.html match intended behavior for each tab
    • Confirm updateTabList.js try/catch silently handles cases where Vue instance is unavailable without breaking other functionality

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Replace jQuery tab visibility with Vue reactivity (Fixes #4700)' directly and concisely describes the main change, referencing both the old approach and new approach.
Description check ✅ Passed The PR description comprehensively covers all template requirements including overview, specific changes, rationale, testing approach, and issue reference.
Linked Issues check ✅ Passed The code changes fully address issue #4700 by replacing jQuery DOM manipulation with Vue reactive state (expertMode, v-show bindings) and consolidating visibility logic into templates.
Out of Scope Changes check ✅ Passed All changes are scoped to replacing jQuery tab visibility logic with Vue reactivity; no unrelated modifications are present.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sonarqubecloud
Copy link

@github-actions
Copy link
Contributor

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/index.html (2)

149-149: Simplify feature flag checks with optional chaining.

The pattern FC.FEATURE_CONFIG?.features?.isEnabled && FC.FEATURE_CONFIG.features.isEnabled('X') can be simplified using optional chaining on the method call itself.

Apply this diff to simplify the feature checks:

-                    <li class="tab_osd" v-show="FC.FEATURE_CONFIG?.features?.isEnabled && FC.FEATURE_CONFIG.features.isEnabled('OSD')"><a href="#" i18n="tabOsd" class="tabicon ic_osd" i18n_title="tabOsd"></a></li>
+                    <li class="tab_osd" v-show="FC.FEATURE_CONFIG?.features?.isEnabled?.('OSD')"><a href="#" i18n="tabOsd" class="tabicon ic_osd" i18n_title="tabOsd"></a></li>
-                    <li class="tab_transponder" v-show="FC.FEATURE_CONFIG?.features?.isEnabled && FC.FEATURE_CONFIG.features.isEnabled('TRANSPONDER')"><a href="#" i18n="tabTransponder" class="tabicon ic_transponder" i18n_title="tabTransponder"></a></li>
+                    <li class="tab_transponder" v-show="FC.FEATURE_CONFIG?.features?.isEnabled?.('TRANSPONDER')"><a href="#" i18n="tabTransponder" class="tabicon ic_transponder" i18n_title="tabTransponder"></a></li>
-                    <li class="tab_led_strip" v-show="FC.FEATURE_CONFIG?.features?.isEnabled && FC.FEATURE_CONFIG.features.isEnabled('LED_STRIP')"><a href="#" i18n="tabLedStrip" class="tabicon ic_led" i18n_title="tabLedStrip"></a></li>
+                    <li class="tab_led_strip" v-show="FC.FEATURE_CONFIG?.features?.isEnabled?.('LED_STRIP')"><a href="#" i18n="tabLedStrip" class="tabicon ic_led" i18n_title="tabLedStrip"></a></li>

Also applies to: 151-151, 152-152


146-147: Consider v-if instead of v-show for build-option tabs.

Build options don't change at runtime (they're determined by firmware compilation), so using v-if would remove these tabs from the DOM entirely when not applicable, reducing memory footprint. The v-show directive is better suited for frequently toggled elements like expert mode tabs.

Apply this diff if you prefer conditional rendering for build-option tabs:

-                    <li class="tab_servos" v-show="['USE_SERVOS','USE_WING'].some(opt => FC.CONFIG?.buildOptions?.includes(opt))"><a href="#" i18n="tabServos" class="tabicon ic_servo" i18n_title="tabServos"></a></li>
-                    <li class="tab_gps" v-show="FC.CONFIG?.buildOptions?.includes('USE_GPS')"><a href="#" i18n="tabGPS" class="tabicon ic_gps" i18n_title="tabGPS"></a></li>
+                    <li class="tab_servos" v-if="['USE_SERVOS','USE_WING'].some(opt => FC.CONFIG?.buildOptions?.includes(opt))"><a href="#" i18n="tabServos" class="tabicon ic_servo" i18n_title="tabServos"></a></li>
+                    <li class="tab_gps" v-if="FC.CONFIG?.buildOptions?.includes('USE_GPS')"><a href="#" i18n="tabGPS" class="tabicon ic_gps" i18n_title="tabGPS"></a></li>
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2b6d727 and 2686c3c.

📒 Files selected for processing (3)
  • src/components/init.js (1 hunks)
  • src/index.html (2 hunks)
  • src/js/utils/updateTabList.js (1 hunks)
🧰 Additional context used
🧠 Learnings (9)
📓 Common learnings
Learnt from: haslinghuis
Repo: betaflight/betaflight-configurator PR: 4510
File: src/js/msp.js:384-391
Timestamp: 2025-09-19T20:42:20.332Z
Learning: Complex MSP duplicate handling fixes in Betaflight Configurator can cause infinite loading messages when changing tabs due to disruption of the callback resolution mechanism. Simple code-only duplicate detection (using this.callbacks.some((instance) => instance.code === code)) is the safer approach that preserves tab switching functionality.
Learnt from: haslinghuis
Repo: betaflight/betaflight-configurator PR: 4597
File: src/js/utils/common.js:95-127
Timestamp: 2025-09-09T20:02:33.475Z
Learning: In the Betaflight Configurator codebase, the Chromium v140 compatibility issue with sortSelect was resolved by rewriting the implementation to use native DOM APIs (Array.from, select.options, select.remove, select.add) instead of jQuery DOM manipulation methods (this.children, this.empty().append). The fix still performs DOM operations but avoids the specific jQuery methods that were causing issues in Chromium v140.
Learnt from: haslinghuis
Repo: betaflight/betaflight-configurator PR: 4577
File: src/js/tabs/configuration.js:580-590
Timestamp: 2025-08-22T22:43:45.415Z
Learning: In src/js/tabs/configuration.js, hiding the entire .mag_align_box for API versions < 1.47 is intentional behavior because these MAG alignment options were not present or have changed significantly between API versions. The code has been reorganized for better maintenance.
Learnt from: haslinghuis
Repo: betaflight/betaflight-configurator PR: 4569
File: src/js/tabs/receiver.js:957-960
Timestamp: 2025-08-13T15:13:10.214Z
Learning: In src/js/tabs/receiver.js, the updateInterpolationView() function already contains logic to hide ".rcSmoothing-feedforward-cutoff" when FC.RX_CONFIG.rcSmoothingFeedforwardCutoff === 0, which handles the API ≥ 1.47 case since feedforward cutoff isn't initialized from DOM for newer APIs.
Learnt from: mituritsyn
Repo: betaflight/betaflight-configurator PR: 4526
File: src/js/gui.js:43-43
Timestamp: 2025-06-20T12:35:49.283Z
Learning: In the Betaflight Configurator codebase, tabs in `defaultCloudBuildTabOptions` are conditionally displayed based on firmware build options. The logic in `serial_backend.js` checks `FC.CONFIG.buildOptions` and only adds tabs to `GUI.allowedTabs` if the firmware was built with support for that feature.
Learnt from: haslinghuis
Repo: betaflight/betaflight-configurator PR: 4569
File: src/js/tabs/receiver.js:650-674
Timestamp: 2025-08-13T15:12:48.509Z
Learning: In src/js/tabs/receiver.js, the rcSmoothing-feedforward-cutoff element is a child of rcSmoothing-feedforward-manual in the DOM structure, so hiding the parent automatically hides the child.
📚 Learning: 2025-08-22T22:43:45.415Z
Learnt from: haslinghuis
Repo: betaflight/betaflight-configurator PR: 4577
File: src/js/tabs/configuration.js:580-590
Timestamp: 2025-08-22T22:43:45.415Z
Learning: In src/js/tabs/configuration.js, hiding the entire .mag_align_box for API versions < 1.47 is intentional behavior because these MAG alignment options were not present or have changed significantly between API versions. The code has been reorganized for better maintenance.

Applied to files:

  • src/js/utils/updateTabList.js
  • src/index.html
📚 Learning: 2025-08-13T15:13:10.214Z
Learnt from: haslinghuis
Repo: betaflight/betaflight-configurator PR: 4569
File: src/js/tabs/receiver.js:957-960
Timestamp: 2025-08-13T15:13:10.214Z
Learning: In src/js/tabs/receiver.js, the updateInterpolationView() function already contains logic to hide ".rcSmoothing-feedforward-cutoff" when FC.RX_CONFIG.rcSmoothingFeedforwardCutoff === 0, which handles the API ≥ 1.47 case since feedforward cutoff isn't initialized from DOM for newer APIs.

Applied to files:

  • src/js/utils/updateTabList.js
📚 Learning: 2025-06-20T12:35:49.283Z
Learnt from: mituritsyn
Repo: betaflight/betaflight-configurator PR: 4526
File: src/js/gui.js:43-43
Timestamp: 2025-06-20T12:35:49.283Z
Learning: In the Betaflight Configurator codebase, tabs in `defaultCloudBuildTabOptions` are conditionally displayed based on firmware build options. The logic in `serial_backend.js` checks `FC.CONFIG.buildOptions` and only adds tabs to `GUI.allowedTabs` if the firmware was built with support for that feature.

Applied to files:

  • src/js/utils/updateTabList.js
  • src/index.html
📚 Learning: 2025-09-02T07:45:48.606Z
Learnt from: blckmn
Repo: betaflight/betaflight-configurator PR: 4583
File: src/js/tabs/firmware_flasher.js:949-961
Timestamp: 2025-09-02T07:45:48.606Z
Learning: In src/js/tabs/firmware_flasher.js, the config file loading code path after firmware loading (in the load_file click handler) cannot be reached when UF2 firmware is loaded, according to the maintainer blckmn. This code is maintained for backward compatibility with unified target settings and will be refactored in a future PR.

Applied to files:

  • src/js/utils/updateTabList.js
📚 Learning: 2025-06-27T22:06:49.210Z
Learnt from: haslinghuis
Repo: betaflight/betaflight-configurator PR: 4532
File: src/js/VirtualFC.js:234-234
Timestamp: 2025-06-27T22:06:49.210Z
Learning: In the betaflight-configurator codebase, the VirtualFC.js AUX_CONFIG array must stay synchronized with the betaflight firmware's msp_box.c definitions to ensure proper auxiliary mode functionality. Changes to mode names should follow the firmware source code even if it potentially breaks backward compatibility with saved presets.

Applied to files:

  • src/components/init.js
  • src/index.html
📚 Learning: 2025-09-10T18:26:10.136Z
Learnt from: haslinghuis
Repo: betaflight/betaflight-configurator PR: 4601
File: package.json:125-125
Timestamp: 2025-09-10T18:26:10.136Z
Learning: In betaflight-configurator, dependency updates are handled incrementally - Vue dependencies are updated separately from Vite dependencies for better isolation and maintainability.

Applied to files:

  • src/components/init.js
📚 Learning: 2025-09-19T20:42:20.332Z
Learnt from: haslinghuis
Repo: betaflight/betaflight-configurator PR: 4510
File: src/js/msp.js:384-391
Timestamp: 2025-09-19T20:42:20.332Z
Learning: Complex MSP duplicate handling fixes in Betaflight Configurator can cause infinite loading messages when changing tabs due to disruption of the callback resolution mechanism. Simple code-only duplicate detection (using this.callbacks.some((instance) => instance.code === code)) is the safer approach that preserves tab switching functionality.

Applied to files:

  • src/index.html
📚 Learning: 2025-09-15T15:19:47.087Z
Learnt from: haslinghuis
Repo: betaflight/betaflight-configurator PR: 4611
File: src/tabs/configuration.html:247-249
Timestamp: 2025-09-15T15:19:47.087Z
Learning: In the Betaflight Configurator's configuration.html, duplicate "not found" elements using the same i18n key (like configurationSensorGyroToUseNotFound) may be intentionally placed in different UI sections that are conditionally displayed based on firmware version. The old gyro alignment section (.gyro_alignment_inputs_notfound) is used for older firmware, while the new gyro enable section (.gyro_notfound) is used for firmware 1.47+.

Applied to files:

  • src/index.html
🔇 Additional comments (3)
src/components/init.js (1)

41-42: LGTM! Clean addition of reactive expert mode flag.

The expertMode property is properly initialized and will be reactive within the Vue model, enabling the template-driven tab visibility changes.

src/index.html (2)

91-91: LGTM! Proper two-way binding for expert mode.

The v-model="expertMode" binding correctly synchronizes the checkbox with the Vue reactive state, enabling instant updates to tab visibility.


140-140: LGTM! Expert mode tabs properly controlled by reactive state.

These tabs correctly use v-show="expertMode" for instant visibility toggling when the expert mode checkbox changes.

Also applies to: 145-145, 153-154

Copy link
Member

@VitroidFPV VitroidFPV left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is something that I've been playing with locally, along with loading the tabs themselves with Vue directly. I don't have much time to work on the more complex behind-the-scenes stuff nowadays, I'm thankful that there's effort going into this still 👍

@VitroidFPV
Copy link
Member

Going forward this would be a great way to gate the tab content itself, but this is a great step forward already

Copy link
Member

@haslinghuis haslinghuis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you. We should use Vue more - but occupied working on serial backend never get to it.

@haslinghuis haslinghuis moved this to App in 2025.12.0 Nov 15, 2025
@haslinghuis haslinghuis added this to the 2025.12 milestone Nov 15, 2025
@haslinghuis haslinghuis merged commit 9ac7fad into betaflight:master Nov 15, 2025
7 checks passed
@github-project-automation github-project-automation bot moved this from App to Done in 2025.12.0 Nov 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Replace tab visibility jQuery with Vue reactivity for expert mode and feature-controlled tabs

3 participants